Skip to content

perf(wa-sqlite): prioritize dedicated-worker reads during sync#167

Open
marcus-pousette wants to merge 1 commit into
fix/remote-apply-schedulerfrom
fix/shared-worker-priority-scheduler
Open

perf(wa-sqlite): prioritize dedicated-worker reads during sync#167
marcus-pousette wants to merge 1 commit into
fix/remote-apply-schedulerfrom
fix/shared-worker-priority-scheduler

Conversation

@marcus-pousette

@marcus-pousette marcus-pousette commented Jun 4, 2026

Copy link
Copy Markdown
Collaborator

What

Let foreground engine reads run between background inbound-sync batches in dedicated-worker wa-sqlite clients.

#166 creates an event-loop gap between remote apply batches. This PR adds the small priority scheduler that decides what may use that gap.

Ordering rules

  • Engine read APIs are foreground.
  • Inbound sync appendMany calls are explicitly background.
  • Local writes, generic runner queries, and unannotated RPCs remain normal priority.
  • A foreground read may bypass queued background work only.
  • A normal/local write is an ordering barrier: later reads cannot jump it.
  • At most eight foreground jobs bypass an earlier background job, preventing sustained reads from starving sync.
  • A running SQLite batch is never interrupted; prioritization happens only between RPC batches.

Direct and shared-worker runtimes keep their existing FIFO paths and pay no scheduler overhead. Public write options expose only background; foreground remains an internal read classification, so callers cannot make writes jump sync work.

Why dedicated-worker only

The earlier revision also changed the shared worker's global queue, but its benchmark used one client/port and therefore did not exercise cross-tab scheduling. That unproven scope and its wire-protocol field are removed. A future shared-worker change should begin with a two-port ordering test and benchmark.

Performance evidence

Focused run 29203415286 completed four counterbalanced normal/background trials per case. Values are background-vs-normal deltas between trial medians; negative latency is better.

Dedicated worker / prefill Read p95 Local-write p95 Remote-batch p95
Memory / 0 -12.2% +1.3% +4.0%
Memory / 5k +0.4% +0.0% +1.0%
OPFS / 0 -16.1% +1.1% +0.9%
OPFS / 5k -2.6% -2.9% -2.4%

Every empty-tree trial improved read p95 (memory: 11.3–14.6%; OPFS: 14.4–17.9%). Populated cases stayed near neutral. The largest median latency cost was 4.0% remote-batch p95. Four trials are directional evidence, not a claim of statistical certainty.

The harness's total-duration field included the final integrity read, so this decision deliberately does not use its derived throughput values. Per-operation latency samples and the final-count integrity check are unaffected.

Debloat

  • 8 files, +251/-32, down from the original 19 files, +1,029/-70.
  • Production changes are +113/-32; the rest is a changeset and focused tests.
  • Shared-worker scheduling and RPC priority serialization are removed.
  • Benchmark infrastructure is not part of this production PR.
  • A compact composition regression proves an engine read is classified ahead of two background writes.

Verification

  • Priority scheduler and engine priority composition: 7/7 deterministic tests.
  • treecrdt-sync: 7/7.
  • sync-sqlite's changed backend tests: 3/3.
  • TypeScript builds for interface, protocol, auth, sync-sqlite, sync, benchmark, and wa-sqlite.
  • Formatting and git diff --check pass.
  • Full GitHub build, browser, playground E2E, native-node, and Postgres CI is green.

Dependency

Stacked on #166. Review only this incremental diff.

@marcus-pousette marcus-pousette added performance Measurable runtime, storage, or responsiveness improvement area:sync Sync protocol, reconciliation, transport, discovery, and sync servers area:web Browser, WASM, OPFS, workers, and playground runtime labels Jul 12, 2026
@marcus-pousette marcus-pousette force-pushed the fix/remote-apply-scheduler branch from 7a95c36 to eee9e75 Compare July 12, 2026 13:44
@marcus-pousette marcus-pousette force-pushed the fix/shared-worker-priority-scheduler branch from 94c727d to 5e8e544 Compare July 12, 2026 15:03
@marcus-pousette marcus-pousette changed the title Prioritize foreground reads during background sync perf(wa-sqlite): prioritize reads between sync batches Jul 12, 2026
@marcus-pousette marcus-pousette force-pushed the fix/shared-worker-priority-scheduler branch from 5e8e544 to 18736d0 Compare July 12, 2026 19:04
@marcus-pousette marcus-pousette force-pushed the fix/shared-worker-priority-scheduler branch from 18736d0 to 440acd5 Compare July 12, 2026 19:05
@marcus-pousette marcus-pousette changed the title perf(wa-sqlite): prioritize reads between sync batches perf(wa-sqlite): prioritize dedicated-worker reads during sync Jul 12, 2026
@marcus-pousette marcus-pousette marked this pull request as ready for review July 12, 2026 19:17
@marcus-pousette

Copy link
Copy Markdown
Collaborator Author

/bench

@github-actions

Copy link
Copy Markdown
Contributor

Benchmarks

Triggered by /bench - Run: https://github.com/cybersemics/treecrdt/actions/runs/29234317596
Suite: full - Base command: success - Head command: success
Base: fix/remote-apply-scheduler (eee9e75) - Head: fix/shared-worker-priority-scheduler (440acd5)
Compared entries: 73 - Improved: 29 - Regressed: 44

Impl Storage Workload Base ops/s Head ops/s Δ ops/s Base p50 ms Head p50 ms Δ p50 Status
core-inmem-crdt memory insert-move-100 115609.81 115832.37 +0.19% 1.73 1.73 -0.19%
core-inmem-crdt memory insert-move-1000 14475.55 14410.50 -0.45% 138.16 138.79 +0.45%
core-inmem-crdt memory insert-move-10000 907.51 874.13 -3.68% 22038.34 22880.00 +3.82%
sqlite-node file insert-into-balanced-tree-fanout10-10000 420.30 414.81 -1.31% 2.38 2.41 +1.32%
sqlite-node file insert-into-balanced-tree-fanout10-50000 404.34 385.69 -4.61% 2.47 2.59 +4.84%
sqlite-node file insert-move-100 16655.91 17229.96 +3.45% 12.01 11.61 -3.33%
sqlite-node file insert-move-1000 18513.41 18417.07 -0.52% 108.03 108.59 +0.52%
sqlite-node file insert-move-10000 16038.85 15927.22 -0.70% 1246.97 1255.71 +0.70%
sqlite-node file read-children-payloads-fanout10-10000 14791.35 14199.02 -4.00% 0.74 0.77 +4.17%
sqlite-node file read-children-payloads-fanout10-50000 14897.56 14631.18 -1.79% 0.74 0.75 +1.82%
sqlite-node file sync-balanced-children-cold-start-fanout10-100 392.45 376.75 -4.00% 25.48 26.54 +4.17%
sqlite-node file sync-balanced-children-cold-start-fanout10-1000 388.66 368.81 -5.11% 25.73 27.11 +5.38% 🟡
sqlite-node file sync-balanced-children-cold-start-fanout10-10000 340.69 314.23 -7.77% 29.35 31.82 +8.42% 🟡
sqlite-node file sync-balanced-children-payloads-cold-start-fanout10-100 794.39 737.45 -7.17% 26.44 28.48 +7.72% 🟡
sqlite-node file sync-balanced-children-payloads-cold-start-fanout10-1000 698.63 600.40 -14.06% 30.06 34.98 +16.36% 🟠
sqlite-node file sync-balanced-children-payloads-cold-start-fanout10-10000 560.76 522.99 -6.73% 37.45 40.15 +7.22% 🟡
sqlite-node file sync-one-missing-100 33.34 30.87 -7.42% 29.99 32.40 +8.01% 🟡
sqlite-node file sync-one-missing-1000 10.40 10.10 -2.82% 96.20 98.98 +2.90%
sqlite-node file sync-one-missing-10000 0.34 0.35 +2.48% 2939.09 2867.88 -2.42%
sqlite-node memory insert-into-balanced-tree-fanout10-10000 1469.80 1434.44 -2.41% 0.68 0.70 +2.47%
sqlite-node memory insert-into-balanced-tree-fanout10-50000 1432.27 1450.36 +1.26% 0.70 0.69 -1.25%
sqlite-node memory insert-move-100 19837.62 20169.54 +1.67% 10.08 9.92 -1.65%
sqlite-node memory insert-move-1000 19009.20 18943.91 -0.34% 105.21 105.57 +0.34%
sqlite-node memory insert-move-10000 16547.29 16508.57 -0.23% 1208.66 1211.49 +0.23%
sqlite-node memory read-children-payloads-fanout10-10000 24992.53 25065.57 +0.29% 0.44 0.44 -0.29%
sqlite-node memory read-children-payloads-fanout10-50000 25975.82 25247.32 -2.80% 0.42 0.44 +2.89%
sqlite-node memory sync-balanced-children-cold-start-fanout10-100 418.05 398.60 -4.65% 23.92 25.09 +4.88%
sqlite-node memory sync-balanced-children-cold-start-fanout10-1000 423.03 420.17 -0.67% 23.64 23.80 +0.68%
sqlite-node memory sync-balanced-children-cold-start-fanout10-10000 365.01 358.03 -1.91% 27.40 27.93 +1.95%
sqlite-node memory sync-balanced-children-payloads-cold-start-fanout10-100 837.61 851.84 +1.70% 25.07 24.65 -1.67%
sqlite-node memory sync-balanced-children-payloads-cold-start-fanout10-1000 702.54 744.53 +5.98% 29.89 28.21 -5.64% 🟡
sqlite-node memory sync-balanced-children-payloads-cold-start-fanout10-10000 581.89 579.36 -0.43% 36.09 36.25 +0.44%
sqlite-node memory sync-one-missing-100 31.02 31.48 +1.48% 32.23 31.76 -1.46%
sqlite-node memory sync-one-missing-1000 10.75 10.73 -0.22% 92.98 93.19 +0.22%
sqlite-node memory sync-one-missing-10000 0.36 0.35 -1.41% 2805.01 2845.15 +1.43%
wa-sqlite browser-memory insert-chain-100 2978.85 2967.58 -0.38% 33.57 33.70 +0.38%
wa-sqlite browser-memory insert-chain-1000 417.75 416.75 -0.24% 2393.76 2399.50 +0.24%
wa-sqlite browser-memory insert-move-100 4091.23 4749.47 +16.09% 48.89 42.11 -13.86% 🟠
wa-sqlite browser-memory insert-move-1000 6980.80 7305.14 +4.65% 286.50 273.78 -4.44%
wa-sqlite browser-memory replay-log-100 2780.48 2912.27 +4.74% 35.97 34.34 -4.53%
wa-sqlite browser-memory replay-log-1000 415.96 418.31 +0.57% 2404.10 2390.58 -0.56%
wa-sqlite browser-memory sync-balanced-children-cold-start-fanout10-100 265.18 261.93 -1.22% 37.71 38.18 +1.24%
wa-sqlite browser-memory sync-balanced-children-cold-start-fanout10-1000 262.26 252.37 -3.77% 38.13 39.62 +3.92%
wa-sqlite browser-memory sync-balanced-children-cold-start-fanout10-10000 245.94 263.28 +7.05% 40.66 37.98 -6.59% 🟡
wa-sqlite browser-memory sync-balanced-children-payloads-cold-start-fanout10-100 527.41 528.87 +0.28% 39.82 39.71 -0.28%
wa-sqlite browser-memory sync-balanced-children-payloads-cold-start-fanout10-1000 509.52 525.33 +3.10% 41.22 39.97 -3.01%
wa-sqlite browser-memory sync-balanced-children-payloads-cold-start-fanout10-10000 449.05 466.64 +3.92% 46.77 45.00 -3.77%
wa-sqlite browser-memory sync-one-missing-100 15.88 15.96 +0.53% 62.99 62.66 -0.53%
wa-sqlite browser-memory sync-one-missing-1000 5.20 5.18 -0.49% 192.28 193.21 +0.49%
wa-sqlite browser-memory sync-one-missing-10000 0.30 0.30 +0.20% 3381.86 3375.22 -0.20%
wa-sqlite browser-memory sync-root-children-fanout10-1110 50.38 48.84 -3.06% 39.70 40.95 +3.16%
wa-sqlite browser-opfs-coop-sync insert-chain-100 1179.91 1268.75 +7.53% 84.75 78.82 -7.00% 🟡
wa-sqlite browser-opfs-coop-sync insert-chain-1000 388.15 390.29 +0.55% 2576.32 2562.17 -0.55%
wa-sqlite browser-opfs-coop-sync insert-move-100 2084.64 1966.57 -5.66% 95.94 101.70 +6.00% 🟡
wa-sqlite browser-opfs-coop-sync insert-move-1000 3825.70 3948.78 +3.22% 522.78 506.49 -3.12%
wa-sqlite browser-opfs-coop-sync replay-log-100 1244.40 1283.66 +3.15% 80.36 77.90 -3.06%
wa-sqlite browser-opfs-coop-sync replay-log-1000 388.72 391.81 +0.79% 2572.52 2552.28 -0.79%
wa-sqlite browser-opfs-coop-sync sync-balanced-children-cold-start-fanout10-100 149.59 147.68 -1.28% 66.85 67.71 +1.30%
wa-sqlite browser-opfs-coop-sync sync-balanced-children-cold-start-fanout10-1000 148.94 147.62 -0.88% 67.14 67.74 +0.89%
wa-sqlite browser-opfs-coop-sync sync-balanced-children-cold-start-fanout10-10000 145.21 135.55 -6.65% 68.87 73.77 +7.12% 🟡
wa-sqlite browser-opfs-coop-sync sync-balanced-children-payloads-cold-start-fanout10-100 266.98 256.99 -3.74% 78.66 81.71 +3.89%
wa-sqlite browser-opfs-coop-sync sync-balanced-children-payloads-cold-start-fanout10-1000 253.78 252.18 -0.63% 82.75 83.27 +0.63%
wa-sqlite browser-opfs-coop-sync sync-balanced-children-payloads-cold-start-fanout10-10000 185.88 189.45 +1.92% 112.98 110.84 -1.89%
wa-sqlite browser-opfs-coop-sync sync-one-missing-100 9.62 9.44 -1.91% 103.94 105.96 +1.94%
wa-sqlite browser-opfs-coop-sync sync-one-missing-1000 2.54 2.58 +1.72% 394.05 387.38 -1.69%
wa-sqlite browser-opfs-coop-sync sync-one-missing-10000 0.16 0.17 +1.62% 6104.38 6007.13 -1.59%
wa-sqlite browser-opfs-coop-sync sync-root-children-fanout10-1110 23.37 23.76 +1.68% 85.59 84.17 -1.66%
wasm memory insert-chain-100 52599.02 51511.40 -2.07% 1.90 1.94 +2.11%
wasm memory insert-chain-1000 28616.29 27679.54 -3.27% 34.95 36.13 +3.38%
wasm memory insert-chain-10000 3908.94 3880.34 -0.73% 2558.24 2577.10 +0.74%
wasm memory insert-move-100 36614.97 35835.45 -2.13% 5.46 5.58 +2.18%
wasm memory insert-move-1000 27081.19 26630.77 -1.66% 73.85 75.10 +1.69%
wasm memory insert-move-10000 3948.98 4033.49 +2.14% 5064.60 4958.49 -2.10%

Status: ✅ <5% change | 🟡 5–10% | 🟠 10–30% | 🔴 >30%

Artifacts:

  • base summary: bench-base/benchmarks/summary.json
  • head summary: bench-head/benchmarks/summary.json
  • command logs: bench-base/benchmark.log, bench-head/benchmark.log

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:sync Sync protocol, reconciliation, transport, discovery, and sync servers area:web Browser, WASM, OPFS, workers, and playground runtime performance Measurable runtime, storage, or responsiveness improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant